﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace JiaBao.Core.Plugins
{
    public class PluginFinder : IPluginFinder
    {
        #region 字段
        /// <summary>
        /// 
        /// </summary>
        private IList<PluginDescriptor> _plugins;

        /// <summary>
        /// 
        /// </summary>
        private bool _arePluginsLoaded;
        #endregion


        /// <summary>
        /// 获取符合LoadPluginsMode 的指定类型插件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="loadMode"></param>
        /// <returns></returns>
        public virtual IEnumerable<T> GetPlugins<T>(LoadPluginsMode loadMode = LoadPluginsMode.InstalledOnly) where T : class, IPlugin
        {
            return GetPluginDescriptors<T>(loadMode).Select(p => p.Instance<T>());
        }

        /// <summary>
        /// 获取符合LoadPluginsMode的指定类型插件说明
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="loadMode"></param>
        /// <returns></returns>
        public virtual IEnumerable<PluginDescriptor> GetPluginDescriptors<T>(LoadPluginsMode loadMode) where T : class, IPlugin
        {
            return GetPluginDescriptors(loadMode)
                .Where(p => typeof(T).IsAssignableFrom(p.PluginType));
        }

        /// <summary>
        /// 获取符合LoadPluginsMode的插件说明
        /// </summary>
        /// <param name="loadMode"></param>
        /// <returns></returns>
        public virtual IEnumerable<PluginDescriptor> GetPluginDescriptors(LoadPluginsMode loadMode = LoadPluginsMode.InstalledOnly)
        {
            EnsurePluginsAreLoaded();
            return _plugins.Where(p => CheckLoadMode(p, loadMode));
        }

        /// <summary>
        /// 根据systemName获取插件说明
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="systemName"></param>
        /// <param name="loadMode"></param>
        /// <returns></returns>
        public virtual PluginDescriptor GetPluginDescriptorBySystemName<T>(string systemName, LoadPluginsMode loadMode) where T : class, IPlugin
        {
            return GetPluginDescriptors<T>(loadMode)
               .SingleOrDefault(p => p.SystemName.Equals(systemName, StringComparison.InvariantCultureIgnoreCase));
        }

        #region 内部方法

        /// <summary>
        /// 获取所有已加载插件
        /// </summary>
        protected virtual void EnsurePluginsAreLoaded()
        {
            if (!_arePluginsLoaded)
            {
                var foundPlugins = PluginManager.ReferencedPlugins.ToList();
                foundPlugins.Sort();
                _plugins = foundPlugins.ToList();
                _arePluginsLoaded = true;
            }
        }

        /// <summary>
        /// 检测插件的Installed与加指定LoadPluginsMode是否匹配
        /// </summary>
        /// <param name="pluginDescriptor"></param>
        /// <param name="loadMode"></param>
        /// <returns></returns>
        protected virtual bool CheckLoadMode(PluginDescriptor pluginDescriptor, LoadPluginsMode loadMode)
        {
            if (pluginDescriptor == null)
                throw new ArgumentNullException("pluginDescriptor");

            switch (loadMode)
            {
                case LoadPluginsMode.All:
                    return true;
                case LoadPluginsMode.InstalledOnly:
                    return pluginDescriptor.Installed;
                case LoadPluginsMode.NotInstalledOnly:
                    return !pluginDescriptor.Installed;
                default:
                    throw new Exception("LoadPluginsMode 有错");
            }
        }
        
        #endregion

    }
}
